#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <debug.h>
#include <os_api.h>
#include <device_api.h>
#include <atclient.h>
#include <net/http.h>
#include <lwip/lwip_api.h>

#define TASK_STACK_SIZE (20 * 1024)
static char _task_stack[TASK_STACK_SIZE];

#define APP_CMD_INIT 1
#define APP_CMD_REPORT 2

typedef struct app_msg_s
{
    uint32_t msg;
    void *data;
} app_msg_t;

typedef struct app_data_s
{
    OSTaskRef task;
    OSTimerRef timer;
    OSMsgQRef cmdq;
} app_data_t;

/******************************* thermal monitor *******************************/
#define THERMAL_LEVEL0 70
#define THERMAL_LEVEL1 75
#define THERMAL_LEVEL2 80
#define THERMAL_LEVEL3 85
#define THERMAL_LEVEL4 90
#define THERMAL_LEVEL5 95
#define THERMAL_LEVEL6 100
#define THERMAL_LEVEL7 105

static int thermal_level = 0;
void handle_thermal_level0()
{
    char resp_str[64];

    thermal_level = 0;

    int ret = atclient_send("AT*GRIP=2,0,6,0\r", 150, 1, resp_str, sizeof(resp_str)); // 恢复最大发射功率
    if (ret != 0)
    {
        LOG_PRINTF("AT*GRIP fail");
    }

    lwip_rate_control_buildup(LWIP_DL_DIRECTION, IP_PROTO_TCP, 0, 1, 0); // 恢复最大上下行速率
    lwip_rate_control_buildup(LWIP_UL_DIRECTION, IP_PROTO_TCP, 0, 1, 0);

    LOG_PRINTF("thermal level0");
}

void handle_thermal_level4()
{
    thermal_level = 4;
    lwip_rate_control_buildup(LWIP_DL_DIRECTION, IP_PROTO_TCP, 1, 1, 50 * 1000 * 1000 / 8); // 限制下行速率50M,根据实际情况调整
    LOG_PRINTF("thermal level4");
}

void handle_thermal_level5()
{
    char resp_str[64];

    thermal_level = 5;

    int ret = atclient_send("AT*GRIP=2,3,6,0\r", 150, 1, resp_str, sizeof(resp_str)); // reduce 最大发射功率3dBm
    if (ret != 0)
    {
        LOG_PRINTF("AT*GRIP fail");
    }

    lwip_rate_control_buildup(LWIP_DL_DIRECTION, IP_PROTO_TCP, 1, 1, 50 * 1000 * 1000 / 8); // 限制下行速率50M,根据实际情况调整

    LOG_PRINTF("thermal level5");
}

void handle_thermal_level6()
{
    char resp_str[64];

    thermal_level = 6;
    int ret = atclient_send("AT*GRIP=2,6,6,0\r", 150, 1, resp_str, sizeof(resp_str)); // reduce 最大发射功率6dBm
    if (ret != 0)
    {
        LOG_PRINTF("AT*GRIP fail");
    }

    lwip_rate_control_buildup(LWIP_DL_DIRECTION, IP_PROTO_TCP, 1, 1, 50 * 1000 * 1000 / 8); // 限制下行速率50M,根据实际情况调整

    lwip_rate_control_buildup(LWIP_UL_DIRECTION, IP_PROTO_TCP, 1, 1, 50 * 1000 * 1000 / 8); // 限制上行速率50M,根据实际情况调整

    LOG_PRINTF("thermal level6");
}

void handle_thermal_level7()
{
    char resp_str[64];

    thermal_level = 7;

    int ret = atclient_send("AT*GRIP=2,9,6,0\r", 150, 1, resp_str, sizeof(resp_str)); // reduce 最大发射功率9dBm
    if (ret != 0)
    {
        LOG_PRINTF("AT*GRIP fail");
    }

    lwip_rate_control_buildup(LWIP_DL_DIRECTION, IP_PROTO_TCP, 1, 1, 20 * 1000 * 1000 / 8); // 限制下行速率20M,根据实际情况调整
    lwip_rate_control_buildup(LWIP_UL_DIRECTION, IP_PROTO_TCP, 1, 1, 10 * 1000 * 1000 / 8); // 限制下行速率10M,根据实际情况调整
    lwip_set_adjust_pp_flag(1);                                                             // 限制工作频率pp4
    lwip_manul_adjust_pp(0);

    LOG_PRINTF("thermal level7");
}

void handle_thermal_level8()
{
    thermal_level = 8;

    dev_CtrlPoweroff(0); // 关闭电源

    LOG_PRINTF("thermal level8 power off!");
}

void do_thermal_control()
{
    int celsius;
    int old_thermal_level = thermal_level;

    celsius = dev_GetTemperature();
    LOG_PRINTF("%s: Temperature=%d", __func__, celsius);
    if (celsius < THERMAL_LEVEL0)
    {
        if (thermal_level != 0)
        {
            handle_thermal_level0();
        }
    }
    else if ((celsius >= THERMAL_LEVEL0) && (celsius < THERMAL_LEVEL1))
    {
        thermal_level = 1;
    }
    else if ((celsius >= THERMAL_LEVEL1) && (celsius < THERMAL_LEVEL2))
    {
        thermal_level = 2;
    }
    else if ((celsius >= THERMAL_LEVEL2) && (celsius < THERMAL_LEVEL3))
    {
        thermal_level = 3;
    }
    else if ((celsius >= THERMAL_LEVEL3) && (celsius < THERMAL_LEVEL4))
    {

        if (thermal_level != 4)
        {
            handle_thermal_level4();
        }
    }
    else if ((celsius >= THERMAL_LEVEL4) && (celsius < THERMAL_LEVEL5))
    {
        if (thermal_level != 5)
        {
            handle_thermal_level5();
        }
    }
    else if ((celsius >= THERMAL_LEVEL5) && (celsius < THERMAL_LEVEL6))
    {
        if (thermal_level != 6)
        {
            handle_thermal_level6();
        }
    }
    else if ((celsius >= THERMAL_LEVEL6) && (celsius < THERMAL_LEVEL7))
    {
        if (thermal_level != 7)
        {
            handle_thermal_level7();
        }
    }
    else if (celsius >= THERMAL_LEVEL7)
    {
        if (thermal_level != 8)
        {
            handle_thermal_level8();
        }
    }

    if (old_thermal_level >= 7 && thermal_level < 7)
    {
        lwip_set_adjust_pp_flag(0); // handle_thermal_level7 禁止了LWIP 自动调整PP 恢复LWIP自动调节
    }
}
/******************************* thermal monitor *******************************/

/******************************* App base *******************************/
static int app_send_msg(app_data_t *ad, uint32_t msg_id, void *data)
{
    app_msg_t msg;

    memset(&msg, 0, sizeof(msg));
    msg.msg = msg_id;
    msg.data = data;
    if (OS_SUCCESS == OSAMsgQSend(ad->cmdq, sizeof(msg), (UINT8 *)&msg, OS_NO_SUSPEND))
    {
        return 0;
    }
    return -1;
}

static void app_init_timer_cb(UINT32 param)
{
    app_data_t *ad = (app_data_t *)param;
    app_send_msg(ad, APP_CMD_INIT, NULL);
}

static void app_report_timer_cb(UINT32 param)
{
    app_data_t *ad = (app_data_t *)param;
    app_send_msg(ad, APP_CMD_REPORT, NULL);
}

static void app_init(app_data_t *ad)
{
    LOG_PRINTF("%s: +", __func__);
    OSATimerStart(ad->timer, SEC2TICKS(10), SEC2TICKS(5), app_report_timer_cb, (UINT32)ad);
    LOG_PRINTF("%s: -", __func__);
}

static void app_report(app_data_t *ad)
{
    LOG_PRINTF("%s: +", __func__);
    do_thermal_control();
    LOG_PRINTF("%s: -", __func__);
}

static void app_task(void *param)
{
    app_data_t *ad = (app_data_t *)param;
    int ret;
    app_msg_t msg;

    while (1)
    {
        memset(&msg, 0, sizeof(msg));
        ret = OSAMsgQRecv(ad->cmdq, (UINT8 *)&msg, sizeof(msg), OS_SUSPEND);
        ASSERT(ret == OS_SUCCESS);
        switch (msg.msg)
        {
        case APP_CMD_INIT:
            app_init(ad);
            break;
        case APP_CMD_REPORT:
            app_report(ad);
            break;
        default:
            break;
        }
    }
}
/******************************* App base *******************************/

int main()
{
    int ret;
    app_data_t *ad;

    dev_SetAppVersion("thermal-V1.0");

    ad = malloc(sizeof(*ad));
    ASSERT(ad);
    memset(ad, 0, sizeof(*ad));

    ret = OSATimerCreate(&ad->timer);
    ASSERT(ret == OS_SUCCESS);

    ret = OSAMsgQCreate(&ad->cmdq, "app", sizeof(app_msg_t), 10, OS_FIFO);
    ASSERT(ret == OS_SUCCESS);

    ret = OSATaskCreate(&ad->task, _task_stack, TASK_STACK_SIZE, OS_APP_PRIORITY, "app", app_task, ad);
    ASSERT(ret == OS_SUCCESS);

    ret = OSATimerStart(ad->timer, SEC2TICKS(3), 0, app_init_timer_cb, (UINT32)ad);
    ASSERT(ret == OS_SUCCESS);
}
